/*
 * 本文件在MIT许可证条款下发布。
 * 
 * 功能：
 *   本文件主要用于解析设备树二进制文件(DTB)中的CPU和中断控制器信息。
 *   具体功能包括:
 *   - 解析并注册CPU节点信息
 *   - 识别支持的中断控制器类型(EXTIOI、LIOINTC、PCH-PIC、MSI等)
 *   - 获取中断控制器的寄存器地址范围
 *   - 将解析到的信息保存到内核参数中供后续使用
 * 
 * 注意：
 *   1. 本文件仅适用于EFI启动环境
 *   2. 本文件仅适用于LoongArch64架构
 *   3. 本文件仅适用于Haiku内核
 * 
 * 作者：Amor，2025年4月
 */


#include <arch_cpu_defs.h>
#include <arch_dtb.h>
#include <arch_smp.h>
#include <boot/platform.h>
#include <boot/stage2.h>

extern "C"
{
#include <libfdt.h>
}

#include "dtb.h"

// 支持的中断控制器列表
const struct supported_interrupt_controllers
{
    const char *dtb_compat;
    const char *kind;
} kSupportedInterruptControllers[] = {
    {"loongson,extioi", "extioi"},
    {"loongson,liointc", "liointc"},
    {"loongson,pch-pic", "pch-pic"},
    {"loongson,msi", "msi"},
};

void arch_handle_fdt(const void *fdt, int node)
{
    const char *deviceType = (const char *)fdt_getprop(fdt, node,
                                                       "device_type", NULL);

    if (deviceType != NULL)
    {
        if (strcmp(deviceType, "cpu") == 0)
        {
            // 处理CPU节点
            platform_cpu_info *info = NULL;
            arch_smp_register_cpu(&info);
            if (info == NULL)
                return;

            // 获取CPU ID
            info->id = fdt32_to_cpu(*(uint32 *)fdt_getprop(fdt, node,
                                                           "reg", NULL));
            dprintf("cpu\n");
            dprintf("  id: %" B_PRIu32 "\n", info->id);

            // 保存CPU ID到内核参数
            if (info->id < SMP_MAX_CPUS)
            {
                gKernelArgs.arch_args.coreIds[info->id] = info->id;
            }
        }
    }

    // 检查节点兼容性
    int compatibleLen;
    const char *compatible = (const char *)fdt_getprop(fdt, node,
                                                       "compatible", &compatibleLen);

    if (compatible == NULL)
        return;

    // 处理中断控制器
    for (uint32 i = 0; i < B_COUNT_OF(kSupportedInterruptControllers); i++)
    {
        if (dtb_has_fdt_string(compatible, compatibleLen,
                               kSupportedInterruptControllers[i].dtb_compat))
        {

            // 获取中断控制器寄存器地址范围
            addr_range range;
            if (dtb_get_reg(fdt, node, 0, range))
            {
                // 根据中断控制器类型设置对应的地址范围
                if (strcmp(kSupportedInterruptControllers[i].kind, "extioi") == 0)
                {
                    gKernelArgs.arch_args.extioi = range;
                    dprintf("Found EXTIOI controller: %#" B_PRIx64